from scipy.interpolate import interpolate

import vcm_change10
import numpy as np
import pandas as pd

import matplotlib.pyplot as plt

import sys

num_time_split = 5
time = []
for i in range(num_time_split):
    time.append(i)
# 从数据集中读取数据
# 在此处进行更换数据集
vehicle_df = pd.read_csv(
    rf'dataset/vehicle_{num_time_split*10}_new.csv', header=None)  # header=None自动添加列字段
cargo_df = pd.read_csv(
    rf'dataset/cargo_{num_time_split*10}_new.csv', header=None)
# real_data = pd.read_csv('dataset/realdata.csv', header=None)

# real_data_dict = {}
# print(real_data)
# for item in real_data.iterrows():
#     my_container = [item[1][i] for i in range(1, 14)]
#     real_data_dict[item[1][0]] = my_container
# print(real_data_dict)

real_data = pd.read_csv('dataset/new_data.csv', header=None)
real_data_dict = {}
# print(real_data)
for item in real_data.iterrows():
    my_container = [item[1][i] for i in range(0, 4)]
    # print(item[1][0])
    real_data_dict[item[1][0]] = my_container

type_match_list = [['低栏车', '日用百货', 0.8], ['低栏车', '特殊货物', 0.3], ['低栏车', '机器零件', 1],
                   ['低栏车', '生鲜果蔬', 0.5],
                   ['低栏车', '砂石散货', 0.8], ['低栏车', '五金机械', 1],
                   ['高栏车', '日用百货', 0.8], ['高栏车', '特殊货物', 0.5], ['高栏车', '机器零件', 1],
                   ['高栏车', '生鲜果蔬', 0.5],
                   ['高栏车', '砂石散货', 1], ['高栏车', '五金机械', 1],
                   ['厢式车', '日用百货', 1], ['厢式车', '特殊货物', 0.8], ['厢式车', '机器零件', 1],
                   ['厢式车', '生鲜果蔬', 0.5],
                   ['厢式车', '砂石散货', 0.8], ['厢式车', '五金机械', 1],
                   ['冷藏车', '日用百货', 0.1], ['冷藏车', '特殊货物', 0.1], [
                       '冷藏车', '机器零件', 0.1],
                   ['冷藏车', '生鲜果蔬', 1],
                   ['冷藏车', '砂石散货', 0.1], ['冷藏车', '五金机械', 0.1],
                   ['通风箱车', '日用百货', 0.8], ['通风箱车', '特殊货物', 0.5], [
                       '通风箱车', '机器零件', 0.8],
                   ['通风箱车', '生鲜果蔬', 1],
                   ['通风箱车', '砂石散货', 0.5], ['通风箱车', '五金机械', 0.8],
                   ['平板车', '日用百货', 0.6], ['平板车', '特殊货物', 0.6], [
                       '平板车', '机器零件', 0.8],
                   ['平板车', '生鲜果蔬', 0.6],
                   ['平板车', '砂石散货', 0.5], ['平板车', '五金机械', 0.8]]

w1 = 0.16
w2 = 0.09
w3 = 0.47
w4 = 0.28
w5 = 0
w6 = 0

(doubleS_list, vehicleAttrMatch_list, cargo_attr_match_list, vehicle_type_match_list,
 vehicle_load_match_list, vehicle_flow_match_list, vehicle_time_match_list,
 vehicle_price_match_list, cargo_time_match_list, cargo_load_match_list, cargo_price_match_list, tocargo_match_list) \
    = [], [], [], [], [], [], [], [], [], [], [], []


class TransportMatchingEnv:

    def __init__(self, num_vehicles=10, num_cargos=10):
        """
        TODO: 1.每个时间片的匹配成功率2.最终的匹配成功率
        :param num_vehicles:
        :param num_cargos:
        """
        self.data = []
        # 当前所处时间片，
        self.num_vehicles = num_vehicles
        self.num_cargos = num_cargos
        # 匹配情况
        self.vehicles_matched = [0] * num_vehicles
        self.cargos_matched = [0] * num_cargos
        # 概率均值
        self.vcm_pro_mean = 0.3
        # 最大值
        self.max_vehicle_index = 0
        self.max_cargo_index = 0
        self.vehicle_queue, self.cargo_queue = {}, {}
        self.vehicle_queue, self.cargo_queue, self.vehicle_prior, self.cargo_prior = (
            self.init_time(self.vehicle_queue, self.cargo_queue,
                           self.max_vehicle_index, self.max_cargo_index))
        # 协商情况
        self.negotiation = np.zeros((10, 10))
        # 当前所处时间片
        self.time_split = 0
        # 成功匹配的索引列表
        self.vehicle_success_match = []
        self.cargo_success_match = []
        # 成功匹配的信息，（车辆id，货物id，双方的综合匹配度）
        self.success_match = []
        # 每个时间片的奖励和
        self.rewards = []
        # 每个时间片运行的次数
        # 在时间片增加时，需要修改
        self.time_episode = {}
        for i in range(num_vehicles):
            self.time_episode[i] = 0
        # 在时间片增加时，需要修改,修改为一个二维数组，num_time_split * ?
        self.reward_list = []
        for i in range(num_time_split):
            self.reward_list.append([0])
        # self.reward1, self.reward2, self.reward3, self.reward4 = [], [], [], []
        # 动作有效空间
        self.action_validity = np.ones((10, 10), dtype=bool)
        # 已经匹配的信息
        self.matched_information = {}
        # 未匹配的信息
        self.not_matched_information = {}
        # 成功率记录
        self.success_rate = []
        self.vehicle_total_success = []
        self.cargo_total_success = []
        # 计算共有多少车和货物匹配成功
        self.count = 0
        # 总奖励
        self.total_reward = 0

    def reset(self):
        """

        :return: 最终返回一个状态，状态包含
        :negotiation: 协商状态
        :matched information:已经分配货物的信息
        :not matched information:未分配货物的信息
        """
        self.vehicles_matched = [0] * 10
        self.cargos_matched = [0] * 10
        # 概率均值
        self.vcm_pro_mean = 0.3
        # 最大值
        self.max_vehicle_index = 0
        self.max_cargo_index = 0
        self.vehicle_queue, self.cargo_queue = {}, {}
        self.vehicle_queue, self.cargo_queue, self.vehicle_prior, self.cargo_prior = (
            self.init_time(self.vehicle_queue, self.cargo_queue,
                           self.max_vehicle_index, self.max_cargo_index))
        # 协商情况
        self.negotiation = np.zeros((10, 10))
        # 当前所处时间片
        self.time_split = 0
        # 成功匹配的索引列表
        self.vehicle_success_match = []
        self.cargo_success_match = []

        # 匹配和未匹配的vehicle和cargo的信息
        self.matched_vehicle_information = np.zeros((10, 9))
        self.not_matched_vehicle_information = np.zeros((10, 9))
        for index, vehicle in self.vehicle_queue:
            self.not_matched_vehicle_information[index - 1] = [vehicle[1], vehicle[2], vehicle[3], vehicle[4][0],
                                                               vehicle[4][1],
                                                               vehicle[5][0], vehicle[5][1],
                                                               vehicle[8][0], vehicle[8][1]]
        self.matched_cargo_information = np.zeros((10, 9))
        self.not_matched_cargo_information = np.zeros((10, 9))
        for index, cargo in self.cargo_queue:
            self.not_matched_cargo_information[index -
                                               1] = [cargo[1], cargo[2], cargo[3], cargo[4][0], cargo[4][1],
                                                     cargo[5][0], cargo[5][1], cargo[8][0], cargo[8][1]]
        # self.not_matched_cargo_information = {}
        state = np.concatenate((
            self.negotiation.flatten(),
            self.matched_vehicle_information.flatten(),
            self.not_matched_vehicle_information.flatten(),
            self.matched_cargo_information.flatten(),
            self.not_matched_cargo_information.flatten(),

            [self.time_split], [self.time_split]
        ))
        self.action_validity = np.ones((10, 10), dtype=bool)
        # 已经分配的货物信息
        self.matched_information = {}
        # 未分配的货物信息
        self.not_matched_information = {}
        # 四个时间片各自的成功率
        # self.success_rate = []
        # 总的匹配成功的车辆和货物
        self.vehicle_total_success = []
        self.cargo_total_success = []
        self.count = 0
        self.total_reward = 0
        self.success_rate = []
        return state

    def valid_actions(self):
        # 返回所有有效动作的列表
        return np.flatnonzero(self.action_validity)

    def update_action_validity(self, action):
        # 更新动作空间有效性矩阵
        row, col = divmod(action, 10)  # 假设动作被编码为0到99
        self.action_validity[row, :] = False
        self.action_validity[:, col] = False

    def init_time(self, vehicle_queue, cargo_queue, max_vehicle_index, max_cargo_index):
        """

        :return:
        """
        # print('当前时间为t=', t)
        # 从数据集中读取车辆的数据-不够十辆

        vehicle_queue = vcm_change10.appendVehicle(
            vehicle_df, vehicle_queue, max_vehicle_index)
        # 从数据集中读取货物的数据
        cargo_queue = vcm_change10.appendCargo(
            cargo_df, cargo_queue, max_cargo_index)
        # 获得车辆和货物的属性概率分布（先验概率）
        # 根据车辆和货物队列中的各个货物的信息计算各个属性占所有车辆和货物特征属性的分布规律
        # print(f'vehicle_queue,cargo_queue:{vehicle_queue, cargo_queue}')
        vehicle_prior = vcm_change10.vehicleAttrDis(vehicle_queue)
        cargo_prior = vcm_change10.cargoAttrDis(cargo_queue)
        # print('车辆的先验概率', vehicle_prior)
        # print('货物先验概率：', cargo_prior)
        # 将10辆车和十个货物得到的10*10的概率值转化为Dataframe分别是pd.DataFrame的列索引，行索引，值
        # vcm_pro_column = []  # 车辆
        # vcm_pro_row = []  # 货物
        # vcm_pro_value = []  # 车辆与货物匹配的概率值
        # 得到此时队列中车辆的索引
        # for vehicleKey, vehicleValue in vehicle_queue.items():
        #     vcm_pro_row.append(vehicleKey)
        # # 得到此时队列中货物的索引
        # for cargoKey, cargoValue in cargo_queue.items():
        #     vcm_pro_column.append(cargoKey)

        vehicles = list(vehicle_queue.items())
        cargos = list(cargo_queue.items())
        return vehicles, cargos, vehicle_prior, cargo_prior

    def decode_action(self, action):
        """
        将一个数字转化为一个二元组
        例如87为(8,7)

        state:bvccxcvbhmhmhk(车货匹配，infortion) da
        action:new state ,reward 好：网络优化 坏：优化dahsiolg.v.sf几【和平5企鹅如今我【怕豪哥biter0【a-8hiubt-0d[r'sike=【4二狗距报名【贴‘’weovyh965t、
        ，kret09bvhy3i-57hynbeigj9v8后浪34qaiuhwgfo0jku2、j0w3vm8eu0fcV姐茂南区qd
        reward:




        :return:
        """
        vehicle_index, cargo_index = int(action / 10), action % 10
        return vehicle_index, cargo_index

    def step(self, action):
        """
        判断是哪个时间片
        方法：
        问题：每个时间片的匹配成功率，如何计算匹配成功率
        2.每个时间片成功率的意义
        3.如何定义是否成功
        idea：
        1.试着直接求出所有时间片下的结果
        2.分时间片
        马尔科夫决策过程：
        state: (1) negotiation,
        :param action:
        :param reward: reward = 0.75*属性匹配度 + 0.25 * 先验概率
        :return:
        """
        # print(f'vehicles,cargos:{self.vehicles, self.cargos}')\
        # print(f'time_split:{self.time_split}')
        # print(f'step action:{action}')
        vehicle_index, cargo_index = self.decode_action(action)

        # vehicle_index = vehicle_index - 1
        # cargo_index = cargo_index - 1
        state = np.concatenate((
            self.negotiation.flatten(),
            self.matched_vehicle_information.flatten(),
            self.not_matched_vehicle_information.flatten(),
            self.matched_cargo_information.flatten(),
            self.not_matched_cargo_information.flatten(),
            [self.time_split], [self.time_split]
        ))
        if self.vehicles_matched[vehicle_index] or self.cargos_matched[cargo_index]:
            if np.sum(self.negotiation) == 10:
                return state, 0, True, self.negotiation
            else:
                return state, 0, False, self.negotiation
        self.update_action_validity(action=action)
        attr_match_list = vcm_change10.VCM(self.vehicle_queue[vehicle_index][1], self.cargo_queue[cargo_index][1],
                                           real_data_dict,
                                           w1, w2,
                                           w3, w4, w5, w6)

        if attr_match_list[len(attr_match_list) - 1] == 0:
            # 如果属性匹配度为0，则最终的匹配度为0
            finalMatch = 0
        else:
            # prior为先验概率 - 环境匹配度 TODO
            (doubleS, vehicleAttrMatch, vehicle_type_match,
             vehicle_load_match, vehicle_flow_match, vehicle_time_match, tocargo_match
             , sign) = attr_match_list
            doubleS_list.append(doubleS)
            vehicleAttrMatch_list.append(vehicleAttrMatch)
            vehicle_type_match_list.append(vehicle_type_match)
            vehicle_load_match_list.append(vehicle_load_match)
            vehicle_flow_match_list.append(vehicle_flow_match)
            vehicle_time_match_list.append(vehicle_time_match)
            tocargo_match_list.append(tocargo_match)
            finalMatch = doubleS
        self.match(vehicle_id=vehicle_index,
                   cargo_id=cargo_index, final_degree=finalMatch)
        reward = finalMatch
        self.count = self.count + 1
        self.total_reward += reward
        self.rewards.append(reward)
        self.matched_vehicle_information[vehicle_index] = [self.vehicle_queue[vehicle_index][1][1],
                                                           self.vehicle_queue[vehicle_index][1][2],
                                                           self.vehicle_queue[vehicle_index][1][3],
                                                           self.vehicle_queue[vehicle_index][1][4][0],
                                                           self.vehicle_queue[vehicle_index][1][4][1],
                                                           self.vehicle_queue[vehicle_index][1][5][0],
                                                           self.vehicle_queue[vehicle_index][1][5][1],
                                                           self.vehicle_queue[vehicle_index][1][8][0],
                                                           self.vehicle_queue[vehicle_index][1][8][1], ]
        self.not_matched_vehicle_information[vehicle_index] = [0, 0, 0, 0, 0, 0, 0, 0, 0]
        self.matched_cargo_information[cargo_index] = [self.cargo_queue[cargo_index][1][1],
                                                       self.cargo_queue[cargo_index][1][2],
                                                       self.cargo_queue[cargo_index][1][3],
                                                       self.cargo_queue[cargo_index][1][4][0],
                                                       self.cargo_queue[cargo_index][1][4][1],
                                                       self.cargo_queue[cargo_index][1][5][0],
                                                       self.cargo_queue[cargo_index][1][5][1],
                                                       self.cargo_queue[cargo_index][1][8][0],
                                                       self.cargo_queue[cargo_index][1][8][1]
                                                       ]
        self.not_matched_cargo_information[cargo_index] = [0, 0, 0, 0, 0, 0, 0, 0, 0]
        if np.sum(self.negotiation) == 10:
            # 如果有进行match的综合匹配度< 0.35，则匹配不成功，从匹配成功的队列中剔除
            self.check_success()
            # print(f'time_split:{self.time_split}')
            # print(f'negotiation')
            # for i in range(len(self.negotiation)):
            #     print(self.negotiation[i])
            # print(f'success match:')
            # for s in self.success_match:
            #     print(f'success_match:{s}')
            # print(f'成功率:{float(len(self.success_match) / 10.)}')
            # 将每个时间片的成功率加入一个列表
            self.success_rate.append(float(len(self.success_match) / 10.))
            # self.rewards = []
            # self.render()
            done = True
            # print(self.time_split)
            # print(f'vehicle_queue:\n{self.vehicle_queue}')
            # if self.time_split == 0:
            #     self.reward1.append(np.sum(self.rewards))
            # elif self.time_split == 1:
            #     self.reward2.append(np.sum(self.rewards))
            # elif self.time_split == 2:
            #     self.reward3.append(np.sum(self.rewards))
            # elif self.time_split == 3:
            #     self.reward4.append(np.sum(self.rewards))
            self.reward_list[self.time_split].append(np.sum(self.rewards))
            if self.time_split == num_time_split - 1:
                # 跳出循环
                done = True
            elif self.time_split != num_time_split - 1:
                # 时间片+1
                self.time_split = self.time_split + 1
                # 如果不是第三个时间片，那就继续进行
                done = False
                # 更新策略
                self.reset_time()
            self.rewards = []

        else:
            done = False

        state = np.concatenate((
            self.negotiation.flatten(),
            self.matched_vehicle_information.flatten(),
            self.not_matched_vehicle_information.flatten(),
            self.matched_cargo_information.flatten(),
            self.not_matched_cargo_information.flatten(),
            [self.time_split], [self.time_split]
        ))
        return state, reward * 10000, done, attr_match_list

    def reset_time(self):
        """
        在每个时间片结束后进行rest
        :return:
        """
        # TODO 修改vehiclequeue和cargo_queue的弹出，目前success_match比较正常，没有问题
        # print(f'time_split:\n{self.time_split}')
        # print(f'self.vehicle_queue:\n{self.vehicle_queue}')
        # print(f'self.cargo_queue:\n{self.cargo_queue}')
        # print(f'self.success_match:\n{self.success_match}')

        self.negotiation = np.zeros((10, 10))
        self.vehicles_matched = [0] * 10
        self.cargos_matched = [0] * 10
        self.vehicle_queue, self.cargo_queue = {}, {}
        self.vehicle_queue, self.cargo_queue, self.vehicle_prior, self.cargo_prior = \
            self.init_time(self.vehicle_queue,
                           self.cargo_queue,
                           self.max_vehicle_index,
                           self.max_cargo_index)
        self.action_validity = np.ones((10, 10), dtype=bool)
        self.success_match = []

    def match(self, vehicle_id, cargo_id, final_degree):
        """

        :param vehicle_id:
        :param cargo_id:
        :return:
        """
        # print(f'vehicle_id:{vehicle_id}\ncargo_id:{cargo_id}')

        # 执行匹配动作
        self.vehicles_matched[vehicle_id] = 1
        self.cargos_matched[cargo_id] = 1
        # print(f'vehicle_id,cargo_id:{vehicle_id, cargo_id}')
        self.negotiation[vehicle_id][cargo_id] = 1
        # 成功匹配的列表,1*10的简单列表

        # 匹配成功的列表（车辆id，货物id，双方的综合匹配度）
        # 成功匹配的信息(vehicle_id,cargo_id,final_degree)
        self.success_match.append((vehicle_id, cargo_id, final_degree))
        # TODO
        # self.vehicle_queue.remove()
        # 更新目前队列的最大值
        if vehicle_id > self.max_vehicle_index:
            self.max_vehicle_index = vehicle_id
        if cargo_id > self.max_cargo_index:
            self.max_cargo_index = cargo_id

    def check_success(self):
        """
        在每次的negotiation填满之后，选择其中效果较差的组合，剔除
        :return:
        """
        success_index_queue = []
        for index, (item1, item2, item3) in enumerate(zip(self.success_match, self.vehicle_queue, self.cargo_queue)):
            # 针对本序列的综合匹配度，如果小于0.35，则匹配失败，将其剔除
            # print(f'item1:\n{item1}\nitem2:\n{item2}')
            # print(f'item1:{item1}')
            # if item1[2] >= 0.35:
            if item1[2] >= 0.35:
                success_index_queue.append(index)
            # if item1[2] < 0.35:
            if item1[2] < 0.35:
                # self.success_match.remove(item1)
                vehicle_id, cargo_id = item1[0], item1[1]
                self.negotiation[vehicle_id][cargo_id] = 0
                # vehicle_queue 10个
                # 根据索引删除vehicle_queue,和cargo_queue中的数据，剩下的数据包含到下一个时间片中，再补全为10个
                # print(f'item[0]:{item1[0]}\nitem[1]:{item1[1]}\nitem[2]:{item1[2]}\n')
                # TODO 更新vehicle and cargo的队列，供下一个时间片进行使用
        self.vehicle_queue = [item for i, item in enumerate(
            self.vehicle_queue) if i not in success_index_queue]
        self.cargo_queue = [item for i, item in enumerate(
            self.cargo_queue) if i not in success_index_queue]
        self.success_match = [item for i, item in enumerate(
            self.success_match) if i in success_index_queue]

    def render(self):
        """
        显示当前的决策方案
        :return:
        """
        plt.imshow(self.negotiation, cmap='viridis', interpolation='nearest')
        plt.colorbar()
        plt.show()

    def compute_reward(self):
        """
        计算一轮下来的reward
        :return:
        """
        w = 0.5
        # 匹配数量权重
        length_weight = self.count / 10. * w
        #
        reward_weight = self.total_reward
        return length_weight + reward_weight

    def draw(self,name):
        def deal_data(data):
            return [np.mean(group)/1.4 for group in
                    np.array_split(data, len(data) // (num_time_split * 10))]

        data = {
            "doubleS": deal_data(doubleS_list),
            "vehicleAttrMatch": deal_data(vehicleAttrMatch_list),
            "vehicle_type_match": deal_data(vehicle_type_match_list),
            "vehicle_load_match": deal_data(vehicle_load_match_list),
            "vehicle_flow_match": deal_data(vehicle_flow_match_list),
            "vehicle_time_match": deal_data(vehicle_time_match_list),
        }
        self.data = data
        df = pd.DataFrame(dict([(k, pd.Series(v)) for k, v in data.items()]))
        df.to_csv(f'{name}_v{num_time_split * 10}_c{num_time_split * 10}_data.csv', index=False)
        print('数据已经成功存储')

        def moving_average(data, window_size):
            return np.convolve(data, np.ones(window_size) / window_size, mode='valid')

        # 设置平滑窗口大小
        window_size = 100
        # original_length = data
        # new_indices = np.linspace(0, original_length - 1, new_length)
        # interpolator = interpolate.interp1d(np.arange(original_length), original_data, kind='linear')
        # new_data = interpolator(new_indices)
        # 为每个属性生成单独的平滑折线图
        for key, value in data.items():
            smoothed_value = moving_average(value, window_size)
            plt.figure()
            plt.plot(range(len(smoothed_value)), smoothed_value, label=f'{key}')
            plt.xlabel('Index')
            plt.ylabel('Value')
            plt.title(f'{key}')
            plt.legend()
            plt.show()
        #
        for key,value in data.items():
            original_length = len(value)
            new_length = 2000
            new_indices = np.linspace(0, original_length - 1, new_length)


            interpolator = interpolate.interp1d(np.arange(original_length), value, kind='linear')
            value = interpolator(new_indices)

            data1 = {
                "value": value/1.4
            }
            df = pd.DataFrame(dict([(k, pd.Series(v)) for k, v in data1.items()]))
            df.to_csv(f'{name}_v{num_time_split * 10}_c{num_time_split * 10}_value.csv', index=False)

            smoothed_value = moving_average(value, window_size)
            plt.figure()
            plt.plot(range(len(smoothed_value)), smoothed_value, label=f'{key}')
            plt.xlabel('Index')
            plt.ylabel('Value')
            plt.title(f'{key}')
            plt.legend()
            plt.show()
            break
def convert_element(element):
    if element.isdigit():  # Check if the element is a digit
        return int(element)
    try:
        # Attempt to convert to a list or tuple if applicable
        return eval(element)
    except:
        # Return the element as is if it's not a digit or list/tuple
        return element


if __name__ == '__main__':

    env = TransportMatchingEnv(40, 40)
    for vehicle in env.vehicle_queue:
        print(vehicle)
